#ifndef WINFUNCTIONS_H
#define WINFUNCTIONS_H

#include <list>
#include <vector>

#include <boost/utility.hpp>
#include <boost/intrusive_ptr.hpp>

//Forward declaration.
class AbstractWinFunction;
namespace boost
{
  void intrusive_ptr_add_ref( AbstractWinFunction * inst );
  void intrusive_ptr_release( AbstractWinFunction * inst );
};

/**
* Class represents a absract window function.
* This function has a name and it is callable.
* function prototype looks like this: dooble foo( double i, double w )
* Where i - is position
* w - is window wide.
* Every instance of AbstractWinFunction contains an internal reference count.
* A new instance has 0 as refernce count.
* You can take access to this counter wit the help of function boost::intrusive_ptr_add_ref and boost::intrusive_ptr_add_ref
* @see WinFuncPtr.
*/
class AbstractWinFunction
{
public:
  /*
  * Cinstructor creates a unstance with the name nm.
  * @param nm name of the function.
  */
  AbstractWinFunction( const char* nm ):name(nm),ref(0){};

  virtual ~AbstractWinFunction();

  /**
  * Calculates your function
  * @param i position in the function diapason
  * @param w wide of fuction diapason
  */
  virtual double operator()(double i, double w) const =0;

  /**
  * Return a name of the function. It`s the same what you put into constructor.
  */
  inline const std::string& getName()const{ return name; };

private:
  const std::string	name;
  unsigned int		ref;

  virtual void addRef(void);
  virtual void release(void);

  friend void boost::intrusive_ptr_add_ref( AbstractWinFunction * inst );
  friend void boost::intrusive_ptr_release( AbstractWinFunction * inst );
};

/**
* Usefull type for clients code.
*/
typedef boost::intrusive_ptr<AbstractWinFunction>	WinFuncPtr;

/**
* Auxilary function`s. They are needed for boost::intrusive_ptr handling.
*/
namespace boost
{
  inline void intrusive_ptr_add_ref( AbstractWinFunction * inst )
  {
      inst->addRef();
  };

  inline void intrusive_ptr_release( AbstractWinFunction * inst )
  {
      inst->release();
  };
};


/**
* Class represents a superposition of windowed functions.
*/
class CompositeWinFunction : public AbstractWinFunction
{
private:
  typedef std::list<WinFuncPtr> FuncContainer;
  FuncContainer	functions;

public:
  typedef FuncContainer::iterator iterator;
  typedef FuncContainer::const_iterator const_iterator;

  CompositeWinFunction(const char* name):AbstractWinFunction(name){};
  virtual ~CompositeWinFunction();

  virtual double operator()(double i, double w) const;

  inline void addFunction(WinFuncPtr function);
  void delFunction( const char* name );
  void delFunction( const_iterator it );
  const_iterator find( const char* name ) const;

  inline void clear()
  { functions.clear(); };

  inline const_iterator begin() const
  { return functions.begin(); };

  iterator begin()
  { return functions.begin(); };

  const_iterator end() const
  { return functions.end(); };

  iterator end()
  { return functions.end(); };
};

/**
* Class BufferedWinFunction is wrapper for any class that is implemented interface AbstractWinFunction.
* It creates array with wrapped function results.
*/
class BufferedWinFunction : public AbstractWinFunction
{
private:
  std::vector<double>	buffer;
  WinFuncPtr	function;
  
public:
  BufferedWinFunction( WinFuncPtr func, bool auto_init=true )
    :AbstractWinFunction( std::string(func->getName()).append(" (Buffered)").c_str() )
  {
    function = func;
  };

  virtual ~BufferedWinFunction();
  virtual double operator()(double i, double w) const;

  //Re-calculates actual values.
  virtual void init(double w);
};

/**
* Factory of windowed functions.
*/
class WindowFuncFactory : boost::noncopyable
{
private:
  typedef std::list< WinFuncPtr > FuncContainer;
  FuncContainer	functions;

public:
  typedef FuncContainer::const_iterator const_iterator;
  typedef FuncContainer::iterator iterator;

  static WindowFuncFactory& Instance();

  const WinFuncPtr getFunction( const char* name );
  WinFuncPtr getBufferedFunction( const char* name );

  iterator registerFunction( WinFuncPtr function );
  void unregisterFunction( const char* name );
  void unregisterFunction( iterator& it );

  inline const_iterator begin() const
  { return functions.begin(); };

  iterator begin()
  { return functions.begin(); };

  const_iterator end() const
  { return functions.end(); };

  iterator end()
  { return functions.end(); };
};

#endif //WINFUNCTIONS_H
